package com.gzw.shop.http;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParser;
import com.gzw.shop.App;
import com.gzw.shop.utils.GsonUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

import static android.R.string.ok;

/**
 * Created by JACKYGUO on 2017-03-07.
 */

public class OkHttpHelper {

    private static OkHttpClient okHttpClient;

    private Gson mGson;

    private Handler mHandler;

    private OkHttpHelper() {

        //设置一些超时时间
        okHttpClient = new OkHttpClient().newBuilder()
                .addInterceptor(new LoggingInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .build();
        mGson = new Gson();

        mHandler = new Handler(Looper.getMainLooper());

    }

    public class LoggingInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            //这个chain里面包含了request和response，所以你要什么都可以从这里拿
            Request request = chain.request();

            long t1 = System.nanoTime();//请求发起的时间
            Log.d("okhttpmsg", String.format("发送请求 %s on %s%n%s",
                    request.url(), chain.connection(), request.headers()));

            Response response = chain.proceed(request);

            long t2 = System.nanoTime();//收到响应的时间

            //这里不能直接使用response.body().string()的方式输出日志
            //因为response.body().string()之后，response中的流会被关闭，程序会报错，我们需要创建出一
            //个新的response给应用层处理
            ResponseBody responseBody = response.peekBody(1024 * 1024);

            Log.d("okhttpmsg", String.format("接收响应: [%s] %n返回json:【%s】 %.1fms%n%s",
                    response.request().url(),
                    responseBody.string(),
                    (t2 - t1) / 1e6d,
                    response.headers()));

            return response;
        }
    }

    public static OkHttpHelper getInstance() {
        return new OkHttpHelper();
    }

    /**
     * 调用 okhttp get方法
     *
     * @param url
     * @param callBack
     */
    public void get(String url, Map<String, Object> parmas, BaseCallBack callBack) {
//        Request request = builGetdRequest(url, null, HttpMehtodType.GET);
        Request request = buildGetRequest(url, parmas);
        doRequest(request, callBack);
    }

    /**
     * 调用 okhttp get方法
     *
     * @param url
     * @param callBack
     */
    public void get(String url, BaseCallBack callBack) {

        get(url, null, callBack);
    }

    /**
     * 调用okhttp post方法
     *
     * @param url
     * @param params
     * @param callBack
     */
    public void post(String url, Map<String, Object> params, BaseCallBack callBack) {
        Request request = buildPostRequest(url, params);
        doRequest(request, callBack);
    }


    public void doRequest(final Request request, final BaseCallBack callBack) {

        callBack.onRequestBefore(request);

        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

                callBack.onFailure(call, e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                //响应回调，用来隐藏对话框
                callBack.onResponse(response);

                //如果请求成功，进入成功回调
                if (response.isSuccessful()) {
                    String resultStr = response.body().string();

                    if (callBack.mType == String.class) {
                        //如果是String类型，直接返回
                        callbackSuccess(callBack, response, resultStr);
                    } else {
                        //如果是其他类型，转换一下格式
                        try {
                            Object object = mGson.fromJson(resultStr, callBack.mType);
                            callbackSuccess(callBack, response, object);

                        } catch (JsonIOException e) {
                            callBack.onError(response, response.code(), e);
                        }
                    }
                } else if (response.code() == 401 || response.code() == 402 || response.code() == 403) {
                    callbackTokenError(callBack, response);

                } else {
                    //失败回调
                    callbackError(callBack, response, null);
                }
            }
        });
    }


    private Request buildPostRequest(String url, Map<String, Object> params) {
        return buildRequest(url, params, HttpMehtodType.POST);
    }

    private Request buildGetRequest(String url, Map<String, Object> params) {
        return buildRequest(url, params, HttpMehtodType.GET);
    }

    /**
     * 构建一个request
     *
     * @param url
     * @param params
     * @param mehtodType
     * @return
     */
    private Request buildRequest(String url, Map<String, Object> params, HttpMehtodType mehtodType) {

        Request.Builder builder = new Request.Builder();
        builder.url(url);

        if (mehtodType == HttpMehtodType.GET) {
            url = buildUrlParams(url, params);
            builder.url(url);
            builder.get();
        } else if (mehtodType == HttpMehtodType.POST) {
            RequestBody body = buildFormData(params);
            builder.post(body);
        }

        return builder.build();
    }

    /**
     * 构建一个带参数的url
     *
     * @param url
     * @param params
     * @return
     */
    private String buildUrlParams(String url, Map<String, Object> params) {

        if (params == null)
            params = new HashMap<>(1);

        String token = App.getInstance().getToken();
        if (!TextUtils.isEmpty(token))
            params.put("token", token);


        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            sb.append(entry.getKey() + "=" + (entry.getValue() == null ? "" : entry.getValue().toString()));
            sb.append("&");
        }
        String s = sb.toString();
        if (s.endsWith("&")) {
            s = s.substring(0, s.length() - 1);
        }

        if (url.indexOf("?") > 0) {
            url = url + "&" + s;
        } else {
            url = url + "?" + s;
        }

        return url;
    }

    /**
     * 构建一个requestbody
     *
     * @param params
     * @return
     */
    private RequestBody buildFormData(Map<String, Object> params) {

        FormBody.Builder builder = new FormBody.Builder();
        if (params != null) {

            for (Map.Entry<String, Object> entry : params.entrySet()) {
                builder.add(entry.getKey(), entry.getValue() == null ? "" : entry.getValue().toString());
            }

            String token = App.getInstance().getToken();
            if (!TextUtils.isEmpty(token)) {
                builder.add("token", token);
            }
        }
        return builder.build();
    }

    /**
     * 处理失败token回调
     * 因为处理的时候可能在主线程中刷新UI，所以把他放在子线程
     *
     * @param callBack
     * @param response
     */
    private void callbackTokenError(final BaseCallBack callBack, final Response response) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callBack.onTokenError(response, response.code());
            }
        });
    }

    /**
     * 处理成功回调
     * 因为处理的时候可能在主线程中刷新UI，所以把他放在子线程
     *
     * @param callBack
     * @param response
     * @param object
     */
    private void callbackSuccess(final BaseCallBack callBack, final Response response, final Object object) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callBack.onSuccess(response, object);
            }
        });
    }

    /**
     * 处理失败回调
     * 因为处理的时候可能在主线程中刷新UI，所以把他放在子线程
     *
     * @param callBack
     * @param response
     * @param e
     */
    private void callbackError(final BaseCallBack callBack, final Response response, final Exception e) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                callBack.onError(response, response.code(), e);
            }
        });
    }

    enum HttpMehtodType {
        GET,
        POST
    }
}
